package com.tjvib.service;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import com.tjvib.bean.SensorInfo;
import com.tjvib.common.Callback;
import com.tjvib.event.ScanStatusEvent;
import com.tjvib.sensor.LpmsB2Sensor;
import com.tjvib.sensor.LpmsB2SensorData;
import com.tjvib.sensor.Sensor;
import com.tjvib.util.LogUtil;
import com.tjvib.util.SharedPreferencesUtil;
import com.tjvib.util.ToastUtil;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class LpmsB2SensorService extends SensorService<LpmsB2SensorData> {

    BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();

    List<LpmsB2Sensor> discoveredSensors = new ArrayList<>();
    List<LpmsB2Sensor> connectedSensors = new ArrayList<>();

    IntentFilter filter;


    @Override
    public void onCreate() {
        super.onCreate();
        if (filter == null) {
            filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
            filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
            filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
            registerReceiver(mReceiver, filter);
        }
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    public void startBtDiscovery() {
        synchronized (discoveredSensors) {
            Iterator<LpmsB2Sensor> it = discoveredSensors.iterator();
            while (it.hasNext()) {
                LpmsB2Sensor device = it.next();
                if (device.getConnectionStatus() != LpmsB2Sensor.SENSOR_STATUS_CONNECTED) {
                    it.remove();
                }
            }
        }
        if (btAdapter.isDiscovering()) {
            btAdapter.cancelDiscovery();
        }
        btAdapter.startDiscovery();
        sendMessageToUI(KEY_MESG, "搜索开始", MSG_SENSOR_CONNECTION_ERROR);
    }

    public void stopBtDiscovery() {
        if (btAdapter.isDiscovering()) {
            btAdapter.cancelDiscovery();
        }
    }

    public boolean isBtDiscovery() {
        return btAdapter.isDiscovering();
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // BT Discovery
            if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
                LogUtil.d("ACTION_DISCOVERY_STARTED");
                EventBus.getDefault().post(new ScanStatusEvent(BluetoothAdapter.ACTION_DISCOVERY_STARTED));
            }
            if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                LogUtil.d("ACTION_DISCOVERY_FINISHED");
                EventBus.getDefault().post(new ScanStatusEvent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
            }

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                LogUtil.d("ACTION_FOUND");
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device == null) {
                    LogUtil.e("device == null");
                    return;
                }
                synchronized (discoveredSensors) {
                    if ((device.getName() != null) && (device.getName().length() > 0)) {
                        if (device.getName().contains("LPMS")) {
                            for (ListIterator<LpmsB2Sensor> it = discoveredSensors.listIterator(); it.hasNext(); ) {
                                if (device.getAddress().equals(it.next().getAddress()))
                                    return;
                            }
                            String deviceName = SharedPreferencesUtil.getLpmsb2SensorName(
                                    LpmsB2SensorService.this, device.getAddress());
                            if(deviceName.equals("未知设备")) {
                                discoveredSensors.add(new LpmsB2Sensor(deviceName, device.getAddress()));
                                SharedPreferencesUtil.saveLpmsB2SensorName(LpmsB2SensorService.this,
                                        device.getAddress(), device.getName());
                            }else {
                                deviceName = device.getName();
                                discoveredSensors.add(new LpmsB2Sensor(deviceName, device.getAddress()));
                            }
                            EventBus.getDefault().post(new ScanStatusEvent(BluetoothDevice.ACTION_FOUND));
                        }
                    }
                }
            }
        }
    };

    @Override
    void connectSensor() {

    }

    @Override
    public void connectSensor(String address, Callback callback) {
        LpmsB2Sensor sensor = null;
        for (LpmsB2Sensor s : discoveredSensors) {
            if (s.getAddress().equals(address)) {
                sensor = s;
                break;
            }
        }

        if (sensor == null) {
            callback.onError("该设备未在发现列表中", null);
            return;
        }

        if (sensor.getConnectionStatus() == Sensor.SENSOR_STATUS_CONNECTED) {
            callback.onSuccess("该设备已连接", null);
            return;
        }

        final LpmsB2Sensor sensorToConnect = sensor;

        new Thread(() -> {
            if (!sensorToConnect.connect()) {
                callback.onFail("连接失败", null);
            } else {
                connectedSensors.add(sensorToConnect);
                SharedPreferencesUtil.saveLpmsB2SensorName(LpmsB2SensorService.this,
                        sensorToConnect.getAddress(), sensorToConnect.getDeviceName());
                callback.onSuccess("连接成功", null);
            }
        }).start();
    }

    @Override
    void disconnectSensor() {

    }

    @Override
    public void disconnectSensor(String address, Callback callback) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.disconnect();
                connectedSensors.remove(s);
                break;
            }
        }
        callback.onSuccess("断开成功", null);
    }

    @Override
    public void disconnectAllSensor() {
        for (LpmsB2Sensor s : connectedSensors) {
            s.disconnect();
        }
        connectedSensors.clear();
    }

    @Override
    public void disconnectAllSensor(Callback callback) {
        for (LpmsB2Sensor s : connectedSensors) {
            s.disconnect();
        }
        connectedSensors.clear();
        callback.onSuccess("断开成功", null);
    }

    @Override
    int getSensorConnectionStatus() {
        return 0;
    }

    @Override
    int getSensorConnectionStatus(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getConnectionStatus();
            }
        }
        return -1;
    }

    @Override
    void setStreamFrequency(int freq) {

    }

    @Override
    public void setStreamFrequency(String address, int freq) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setStreamFrequency(freq);
                break;
            }
        }
    }

    @Override
    int getStreamFrequency() {
        return 0;
    }

    @Override
    public int getStreamFrequency(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getStreamFrequency();
            }
        }
        return -1;
    }

    @Override
    LpmsB2SensorData getData() {
        return null;
    }

    @Override
    public LpmsB2SensorData getData(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getData();
            }
        }
        return null;
    }

    @Override
    public void resetTimestamp() {
        if(!LpmsB2Sensor.isRecording()) {
            for (LpmsB2Sensor s : connectedSensors) {
                s.resetTimestamp();
            }
        }else
            ToastUtil.show("结束记录后才能重新设置timestamp");
    }

    @Override
    public void resetTimestamp(String address) {
        if(!LpmsB2Sensor.isRecording()) {
            for (LpmsB2Sensor s : connectedSensors) {
                if (s.getAddress().equals(address)) {
                    s.resetTimestamp();
                    break;
                }
            }
        }else
            ToastUtil.show("结束记录后才能重新设置timestamp");
    }

    @Override
    public void startRecording() {
        LpmsB2Sensor.startRecording(this);
    }

    @Override
    public void stopRecording() {
        LpmsB2Sensor.stopRecording();
    }

    @Override
    public boolean isRecording() {
        return LpmsB2Sensor.isRecording();
    }

    @Override
    public void discardData() {
        LpmsB2Sensor.discardData();
    }

    @Override
    public void storeData(String name, Callback callback) {
        LpmsB2Sensor.storeData(name, callback);
    }

    public int getConnectedSensorsSize() {
        return connectedSensors.size();
    }

    public List<SensorInfo> getLpmsB2SensorInfoList() {
        List<SensorInfo> sensorInfoList = new ArrayList<>();
        for (LpmsB2Sensor sensor : discoveredSensors) {
            if (sensor.getConnectionStatus() == Sensor.SENSOR_STATUS_CONNECTED) {
                SensorInfo info = new SensorInfo(sensor.getDeviceName(), sensor.getAddress(), "connected");
                sensorInfoList.add(info);
            }
            if (sensor.getConnectionStatus() == Sensor.SENSOR_STATUS_CONNECTING) {
                SensorInfo info = new SensorInfo(sensor.getDeviceName(), sensor.getAddress(), "connecting");
                sensorInfoList.add(info);
            }
            if (sensor.getConnectionStatus() == Sensor.SENSOR_STATUS_DISCONNECTED) {
                SensorInfo info = new SensorInfo(sensor.getDeviceName(), sensor.getAddress(), "disconnected");
                sensorInfoList.add(info);
            }
        }

        return sensorInfoList;
    }

    public List<SensorInfo> getConnectedLpmsB2SensorInfoList() {
        List<SensorInfo> result = new ArrayList<>();
        for (LpmsB2Sensor sensor : connectedSensors) {
            SensorInfo info = new SensorInfo(sensor.getDeviceName(), sensor.getAddress(), "connected");
            result.add(info);
        }

        return result;
    }

    public int getImuId(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getImuId();
            }
        }
        return -1;
    }

    public void setImuId(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setImuId(value);
                break;
            }
        }
    }

    public int getGyroRange(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getGyroRange();
            }
        }
        return -1;
    }

    public void setGyroRange(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setGyroRange(value);
                break;
            }
        }
    }

    public int getAccRange(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getAccRange();
            }
        }
        return -1;
    }

    public void setAccRange(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setAccRange(value);
                break;
            }
        }
    }

    public int getMagRange(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getMagRange();
            }
        }
        return -1;
    }

    public void setMagRange(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setMagRange(value);
            }
        }
    }

    public boolean isAccDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isAccDataEnabled();
            }
        }
        return false;
    }

    public boolean isGyroDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isGyroDataEnabled();
            }
        }
        return false;
    }

    public boolean isMagDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isMagDataEnabled();
            }
        }
        return false;
    }

    public boolean isAngularVelDataEnable(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isAngularVelDataEnable();
            }
        }
        return false;
    }

    public boolean isQuaternionDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isQuaternionDataEnabled();
            }
        }
        return false;
    }

    public boolean isEulerDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isEulerDataEnabled();
            }
        }
        return false;
    }

    public boolean isLinAccDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isLinAccDataEnabled();
            }
        }
        return false;
    }

    public boolean isPressureDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isPressureDataEnabled();
            }
        }
        return false;
    }

    public boolean isAltitudeDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isAltitudeDataEnabled();
            }
        }
        return false;
    }

    public boolean isTemperatureDataEnabled(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.isTemperatureDataEnabled();
            }
        }
        return false;
    }

    public void setTransmissionData(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setTransmissionData(value);
                break;
            }
        }
    }

    public int getFilterMode(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                return s.getFilterMode();
            }
        }
        return -1;
    }

    public void setFilterMode(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setFilterMode(value);
                break;
            }
        }
    }

    public void setOrientationOffset(String address, int value) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.setOrientationOffset(value);
                break;
            }
        }
    }

    public void resetOrientationOffset(String address) {
        for (LpmsB2Sensor s : connectedSensors) {
            if (s.getAddress().equals(address)) {
                s.resetOrientationOffset();
                break;
            }
        }
    }
}
